package cn.net.isir.core.shiroFilter;

import cn.net.isir.common.ResultObject;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import java.io.IOException;

/**
 * @author liuxubo
 * @filename ShiroLoginFilter.java
 * @package cn.net.isir.core.shiroFilter
 * @email lxb@isir.net.cn
 * @date 2018/11/26
 * @comment
 * @since 1.8
 */
public class ShiroRestFilter extends HttpMethodPermissionFilter {
    /**
     * Resolves an 'application friendly' action verb based on the {@code HttpServletRequest}'s method, appends that
     * action to each configured permission (the {@code mappedValue} argument is a {@code String[]} array), and
     * delegates the permission check for the newly constructed permission(s) to the superclass
     * {@link PermissionsAuthorizationFilter#isAccessAllowed(ServletRequest, ServletResponse, Object) isAccessAllowed}
     * implementation to perform the actual permission check.
     *
     * @param request     the inbound {@code ServletRequest}
     * @param response    the outbound {@code ServletResponse}
     * @param mappedValue the filter-specific config value mapped to this filter in the URL rules mappings.
     * @return {@code true} if the request should proceed through the filter normally, {@code false} if the
     * request should be processed by this filter's
     * {@link #onAccessDenied(ServletRequest, ServletResponse, Object)} method instead.
     * @throws IOException
     */
    @Override
    public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
        return super.isAccessAllowed(request, response, mappedValue);
    }

    /**
     * Handles the response when access has been denied.  It behaves as follows:
     * <ul>
     * <li>If the {@code Subject} is unknown<sup><a href="#known">[1]</a></sup>:
     * <ol><li>The incoming request will be saved and they will be redirected to the login page for authentication
     * (via the {@link #saveRequestAndRedirectToLogin(ServletRequest, ServletResponse)}
     * method).</li>
     * <li>Once successfully authenticated, they will be redirected back to the originally attempted page.</li></ol>
     * </li>
     * <li>If the Subject is known:</li>
     * <ol>
     * <li>The HTTP {@link HttpServletResponse#SC_UNAUTHORIZED} header will be set (401 Unauthorized)</li>
     * <li>If the {@link #getUnauthorizedUrl() unauthorizedUrl} has been configured, a redirect will be issued to that
     * URL.  Otherwise the 401 response is rendered normally</li>
     * </ul>
     * <code><a name="known">[1]</a></code>: A {@code Subject} is 'known' when
     * <code>subject.{@link Subject#getPrincipal() getPrincipal()}</code> is not {@code null},
     * which implicitly means that the subject is either currently authenticated or they have been remembered via
     * 'remember me' services.
     *
     * @param request  the incoming <code>ServletRequest</code>
     * @param response the outgoing <code>ServletResponse</code>
     * @return {@code false} always for this implementation.
     * @throws IOException if there is any servlet error.
     */
    @Override
    protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
        ResultObject resultObject = new ResultObject();
        resultObject.setResult(ShiroError.REST_ERR_CODE);
        resultObject.setMessage(ShiroError.REST_ERR_MESSAGE);
        try {
            response.getWriter().print(resultObject.toString());
        } catch (IOException e) {
            e.printStackTrace();
        }
        return false;
    }
}
